var http = require('http');
var router = require("./libs/router")
require("libjv");


var log4js = require('log4js');

//https://log4js-node.github.io/log4js-node/layouts.html
let layout = {
    type: 'pattern',
    pattern: '%d{yyyy-MM-dd hh:mm:ss} %p %f{2}:%l %m'
}
log4js.configure({
    appenders: {
        fileout: {type: "file", filename: "logs/nodejs.log", daysToKeep: 20, layout: layout},
        consoleout: {type: "console", layout: layout},
    },
    categories: {
        default: {appenders: ["fileout", "consoleout"], level: "debug", enableCallStack: true}
    }
});

var logger4js = log4js.getLogger();

global.logger = logger4js


Object.defineProperty(Array.prototype, "forEachAsync", {
    async value(filter) {
        var ret = 0;
        if (!this.length || !filter) return ret;

        for (var i = 0, len = this.length; i < len; i++) {
            var item = this[i];
            var ret = await filter(item, i);
            if (ret === false) {
                return ret;
            }
            ret++;
        }
        return ret;
    }, enumerable: false
});

jv.getFunctionInfo = (error) => {
    if (!error || !error.stack) {
        return "";
    }

    var line = 8;


    return (error.stack.split("\n").slice(0, line) || []).join("\n");
};


var program = require('commander');

program
    .version(process.env.npm_package_version)
    .description(process.env.npm_package_name + ":" + process.env.npm_package_version)
    .requiredOption('--port [port]', '端口号', 3000)
    .option('--profile  <profile>', 'profile', 'dev')
    .parse(process.argv);

var opts = program.optsWithGlobals();
var envValues = {};
Object.keys(opts).forEach(it => {
    envValues["argv_" + it] = opts[it];
})

Object.assign(global.process.env, envValues);


//config 不会覆盖配置项。优先级从高到低加载。
var dotEnv = require('dotenv');
dotEnv.config({path: "config/.env." + global.process.env.argv_profile})
dotEnv.config({path: "config/.env"})
dotEnv.config({path: ".env." + global.process.env.argv_profile})
dotEnv.config({path: ".env"})

var port = global.process.env.argv_port || 80;


router.init();
let routes = router.routers;
http.createServer(async function (req, res) {

    if (req.url.startsWith("/health")) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.write("node!")
        res.end();
        return;
    }

    var queryJson = jv.query2Json(req.url);
    jv.requestJson = queryJson;
    var path = queryJson.getUrlPart();
    var route = routes.getRouter(req.method, path);
    if (!route) {
        res.writeHead(404, {'Content-Type': 'text/plain'});
        res.end();
        return;
    }

    var error, result, ctx = {
        queryJson: queryJson,
        path: path,
        request: req,
        response: res
    };


    if (req.method === 'POST' || req.method == "PUT") {
        let body = "";
        req.on('data', chunk => {
            body += chunk.toString(); // 转换为字符串
        });
        req.on('end', () => {
            ctx.postBody = body;

            if ((req.headers["content-type"] || "").includes("json")) {
                ctx.postJson = JSON.parse(body);
            }
        });
    }

    try {
        await req.toArray();
        result = await route(ctx);

        var headers = {};
        if (result) {
            if (result.isSimpleType()) {
                headers['Content-Type'] = 'text/plain';
            } else {
                result = JSON.stringify(result);
                headers['Content-Type'] = 'application/json';
            }

            res.writeHead(200, headers);
            res.write(result);
        } else {
            res.writeHead(200, headers);
        }

    } catch (e) {
        error = e;

        res.contentType = e.contentType;
        res.statusCode = e.status;

        if (!res.statusCode) {
            res.statusCode = 500;
        }

        var msg = e.body;
        if (msg) {
            res.write(msg);
        } else {
            msg = e.message;
            if (msg) {
                res.contentType = "application/json"
                res.write(JSON.stringify({code: -1, msg: msg}));
            }
        }
    } finally {
        if (!res.statusCode) {
            res.statusCode = 200;
        }
        res.end();

        var msg = res.statusCode + " " + req.method + " " + req.url;

        if (req.headers) {
            msg += "\n" + JSON.stringify(req.headers);
        }

        if (req.body) {
            msg += "\n" + req.body;
        }

        if (result) {
            msg += "\n" + result;
        }

        if (error) {
            var errString = error.message || error.body
            if (errString) {
                msg += "\n" + errString
            }

            msg += "\n" + jv.getFunctionInfo(error);
            logger.error(msg)
        } else {
            logger.info(msg)
        }
    }
}).listen(port);


logger.info("端口: " + port)
//
// // logger
// app.use(async (ctx, next) => {
//
// 	ctx.error = msg => {
// 		logger.error(msg);
// 		throw new Error(msg);
// 	};
//
// 	const start = new Date()
// 	await next()
//
// 	const ms = new Date() - start
//
// 	var m = ctx.res.statusCode.Between(200, 399) ? "info" : "error";
// 	logger[m](`[${Date.nowString()}] ${ctx.method} ${ctx.url} ${ctx.res.statusCode} - ${ms}ms`);
// });
//
//
// let route = require("./routes");
//
// route.init(app);
//
// // error-handling
// app.on('error', (err, ctx) => {
// 	global.score_working_start = null;
// 	ctx.res.writeHead(500, {
// 		'content-Type': 'application/json'
// 	});
// 	logger.error(`${ctx.res.statusCode} ${ctx.method} ${ctx.url} ${err.message} ${err.stack}`);
// 	ctx.res.end(JSON.stringify({msg: err.message}));
// });
//
// module.exports = app
